#include "NetworkMessage.h"
#include <cstring>
#include <algorithm>
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")

#ifdef _DEBUG
	#include "../Utility/Misc/DebugOutput.h"
#endif

NetworkMessage::NetworkMessage() : currSize(0), readCount(0)
{
	memset(data, 0, NET_MAX_DATA);
}

NetworkMessage::~NetworkMessage()
{
}

NetworkMessage::NetworkMessage(const NetworkMessage& _NetMsg) : currSize(_NetMsg.currSize), readCount(_NetMsg.readCount)
{
	memcpy(data,_NetMsg.data, NET_MAX_DATA);
}
	
NetworkMessage& NetworkMessage::operator=(const NetworkMessage& _NetMsg)
{
	if(this != &_NetMsg)
	{
		currSize = _NetMsg.currSize;
		readCount = _NetMsg.readCount;
		memcpy(data,_NetMsg.data, NET_MAX_DATA);
	}

	return *this;
}

void NetworkMessage::Clear()
{
	memset(data, 0, NET_MAX_DATA);
	currSize = 0;
	readCount = 0;
}

unsigned char* NetworkMessage::GetSpace(int _size)
{
    unsigned char* tempData;

    if(currSize + _size > NET_MAX_DATA)
    {
        Clear();

#ifdef _DEBUG
		DebugOutput::Print(DebugOutput::NETWORK_MSG, DebugOutput::NETWORKING_FAILURE, "Overloaded Network Message Buffer");
#endif

    }

    tempData = data + currSize;

    currSize += _size;

    return tempData;
}
   
char NetworkMessage::ReadByte()
{
	if(readCount + 1 > currSize)
	{
	    return -1;
	}
	
	char tempByte;

	tempByte = data[readCount++];

    return tempByte;
}

void* NetworkMessage::ReadData(int _size)
{
	if(readCount + _size > currSize)
	{
		return NULL;
	}

	int dataHead = readCount;
	readCount += _size;

	return &data[dataHead];
}
    
short NetworkMessage::ReadShort()
{
	if(readCount + 2 > currSize)
	{
		return -1;
	}

	int	tempShort;

	tempShort = (short)(data[readCount] + (data[readCount + 1] << 8));
	
	readCount += 2;

	return tempShort;
}
    
int NetworkMessage::ReadInt()
{
	if (readCount + 4 > currSize)
	{
		return -1;
	}

	int	tempInt;
	
	tempInt = data[readCount] + (data[readCount + 1] << 8) + (data[readCount + 2] << 16) + (data[readCount + 3] << 24);
	
	readCount += 4;
	
	return tempInt;
}
	
float NetworkMessage::ReadFloat()
{
	if (readCount + 4 > currSize)
	{
		return -1;
	}

	union
	{
		float f;
		int	l;
	} mem;

	mem.l = (data[readCount] << 24) + (data[readCount + 1] << 16) + (data[readCount + 2] << 8) + data[readCount + 3];

	readCount += 4;

	return mem.f;
}



char* NetworkMessage::ReadStringByLen(int _length)
{
	static char	tempString[1024];
	char tempChar;
	int read = 0;

	for( ; read < _length; ++read)
	{
		tempChar = ReadByte();

		tempString[read] = tempChar;
	}
	
	tempString[read] = 0;
	
	return tempString;
}

char* NetworkMessage::ReadUUID()
{
	static char tempID[16];
	char tempNum;

	for(int i = 0; i < 16; ++i)
	{
		tempNum = ReadByte();

		tempID[i] = tempNum;
	}
	
	return tempID;
}

void NetworkMessage::WriteByte(char _byte)
{
	unsigned char* buffer = GetSpace(1);

    buffer[0] = _byte; 
}
    
void NetworkMessage::WriteShort(short _num)
{
	unsigned char* buffer = GetSpace(2);

    buffer[0] = _num & 0xff;
	buffer[1] = _num >> 8;
}

void NetworkMessage::WriteInt(int _num)
{
	unsigned char* buffer = GetSpace(4);

    buffer[0] = _num & 0xff;
	buffer[1] = (_num >> 8) & 0xff;
    buffer[2] = (_num >> 16) & 0xff;
    buffer[3] = _num >> 24;
}
    
void NetworkMessage::WriteString(char* _str)
{
	unsigned char* tempData;
    int _length;

    if(!_str)
    {
        tempData = GetSpace(1);
        strncpy_s((char*)tempData, 1, "", 1);
    }
    else
    {
        _length = (int)strlen(_str) + 1;
        tempData = GetSpace(_length);
        strncpy_s((char*)tempData, _length, _str, _length);
    }
}

void NetworkMessage::WriteFloat(float _num)
{
	unsigned char* buffer = GetSpace(4);

	union
	{
		float f;
		int	l;
	} temp;
		
	temp.f = _num;
	temp.l = htonl(temp.l);

    memcpy(buffer, &temp, 4);
}
   
void NetworkMessage::WriteData(const void *_data, int _size)
{
	memcpy(GetSpace(_size), _data, _size);
}